package com.wonghiu.framework.service.spring;

import com.wonghiu.framework.cluster.directory.ProviderDirectory;
import com.wonghiu.framework.cluster.directory.imp.ZkProviderDirectory;
import com.wonghiu.framework.common.extention.ExtensionLoader;
import com.wonghiu.framework.common.factory.SingletonFactory;
import com.wonghiu.framework.config.HRpcServiceConfig;
import com.wonghiu.framework.proxy.ConsumerProxy;
import com.wonghiu.framework.service.annotation.HRpcReference;
import com.wonghiu.framework.service.annotation.HRpcService;
import com.wonghiu.framework.transport.HRpcRequestTransport;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;

/**
 * @Author wonghiu
 * @Date 2021/8/10 19:30
 * @Version 1.0.1
 */
@Slf4j
@Component
public class HRpcPostProcessor implements BeanPostProcessor, ApplicationContextAware, BeanFactoryAware{
    private final ProviderDirectory serviceProvider;
    private final HRpcRequestTransport rpcClient;
    private ApplicationContext applicationContext;
    private BeanFactory beanFactory;

    public HRpcPostProcessor() {
        this.serviceProvider = SingletonFactory.getInstance(ZkProviderDirectory.class);
        this.rpcClient = ExtensionLoader.getExtensionLoader(HRpcRequestTransport.class).getExtension("netty");
    }

    @SneakyThrows
    @Override
    // 服务暴露 : 注解检查+注册中心发布
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean.getClass().isAnnotationPresent(HRpcService.class)) {
            HRpcService rpcService = bean.getClass().getAnnotation(HRpcService.class);
            HRpcServiceConfig rpcServiceConfig = HRpcServiceConfig.builder()
                    .group(rpcService.group())
                    .version(rpcService.version())
                    .service(bean).build();
            serviceProvider.publishService(rpcServiceConfig);
        }
        return bean;
    }
    // 遍历每一个bean的每一个属性，查看是否属性上有HReference注解，如果有，则为该属性创建一个代理对象，并将Client绑定到该代理对象中
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> targetClass = bean.getClass();
        Field[] declaredFields = targetClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            HRpcReference rpcReference = declaredField.getAnnotation(HRpcReference.class);
            if (rpcReference != null) {
                System.out.println(declaredField.getName());
                Object clientProxy =null;
                if (!beanFactory.containsBean(declaredField.getName())) {
                    HRpcServiceConfig rpcServiceConfig = HRpcServiceConfig.builder()
                            .group(rpcReference.group())
                            .version(rpcReference.version()).build();
                    ConsumerProxy rpcClientProxy = new ConsumerProxy(rpcClient, rpcServiceConfig);
                    clientProxy = rpcClientProxy.getProxy(declaredField.getType());
                    ConfigurableListableBeanFactory registry = (ConfigurableListableBeanFactory) beanFactory;
                    registry.registerSingleton(declaredField.getName(),clientProxy);
                }else {
                    clientProxy = beanFactory.getBean(declaredField.getName());
                }
                declaredField.setAccessible(true);
                try {
                    declaredField.set(bean, clientProxy);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }
        return bean;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory=beanFactory;
    }
}
